//
// Created by Tony on 2024/6/7.
//

#include "SymbolTable.h"
#include <algorithm>
#include <cstdint>

namespace Compiler {

Location SymbolTable::add(const string& symbolName, SymbolType type, int32_t classId) {
    auto index = size();
    auto slotId = static_cast<int16_t>(index + mOffset);
    Symbol symbol{symbolName, type, mScopeType, classId, slotId};
    mSymbols.push_back(symbol);
    mIndexes[symbolName] = index;
    return {index, 0};
}

Symbol SymbolTable::get(Location location) {
    if (location.distance == 0) {
        return mSymbols[location.index];
    }

    if (getOuter() == nullptr) {
        return Symbol{.type = SymbolType::UNKNOWN};
    }

    location.distance--;
    return getOuter()->get(location);
}

Location SymbolTable::where(const string& symbolName) {
    auto index = mIndexes.find(symbolName);
    if (index != mIndexes.end()) {
        return Location{index->second, 0};
    }

    if (getOuter() == nullptr) {
        return Location{-1};
    }

    auto location = getOuter()->where(symbolName);
    location.distance++;
    return location;
}

int16_t SymbolTable::addInner(const shared_ptr<SymbolTable>& symbolTable) {
    auto index = mInners.size();
    mInners.push_back(symbolTable);
    return static_cast<int16_t>(index);
}

shared_ptr<SymbolTable> SymbolTable::getInner(const string& name) {
    for (auto& inner : mInners) {
        if (inner->mName == name) {
            return inner;
        }
    }
    return nullptr;
}

int16_t SymbolTable::addImport(const shared_ptr<SymbolTable>& import) {
    auto index = mImports.size();
    mImports.push_back(import);
    return static_cast<int16_t>(index);
}

shared_ptr<SymbolTable> SymbolTable::getImport(const string& name) {
    for (auto& import : mImports) {
        if (import->mName == name) {
            return import;
        }
    }
    return nullptr;
}

int16_t SymbolTable::maxSlotCount() const {
    int16_t innerMaxSize = 0;
    for (const auto& inner : mInners) {
        innerMaxSize = std::max(inner->size(), innerMaxSize);
    }
    return static_cast<int16_t>(innerMaxSize + size());
}

int16_t SymbolTable::totalSymbolCount() const {
    int totalCount = size();
    for (const auto& inner : mInners) {
        totalCount += inner->size();
    }
    return static_cast<int16_t>(totalCount);
}

} // namespace Compiler
